package com.redis.config;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RBucket;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class RedisClientUtil implements ICache {
    @Resource(name = "redissonClient")
    private RedissonClient client;
//    private static Logger log = Logger.getLogger(RedisClientUtil.class);

    @Override
    public boolean putObject(String key, Object value, long cacheTime) {
        try {
            if (cacheTime < 0) {
                client.getBucket(key).set(value);
            } else {
                client.getBucket(key).set(value, cacheTime, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception ex) {
            log.error("", ex);
            return false;
        }
    }

    @Override
    public Object getObject(String key) {
        RBucket bucket = client.getBucket(key);
        if (bucket != null) {
            return bucket.get();
        }
        return null;
    }

    @Override
    public boolean removeObject(String key) {
        return client.getBucket(key).delete();
    }

    @Override
    public boolean addToList(String key, Object value, long cacheTime) {
        try {
            boolean r = client.getList(key).add(value);
            if (r && cacheTime > 0) {
                client.getList(key).expire(cacheTime, TimeUnit.SECONDS);
            }
            return r;
        } catch (Exception ex) {
            log.error("", ex);
            return false;
        }

    }

    @Override
    public boolean addToList(String key, int index, Object value, long cacheTime) {
        try {
            client.getList(key).add(value);
            if (cacheTime > 0) {
                client.getList(key).expire(cacheTime, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception ex) {
            log.error("", ex);
            return false;
        }
    }

    @Override
    public boolean addAllToList(String key, List values, long cacheTime) {
        try {
            client.getList(key).addAll(values);
            if (cacheTime > 0) {
                client.getList(key).expire(cacheTime, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception ex) {
            log.error("", ex);
            return false;
        }
    }

    @Override
    public Object getFromList(String key, int index) {
        return client.getList(key).get(index);
    }

    @Override
    public Object[] getArrayFromList(String key) {
        if (client.getList(key).isExists()) {
            return client.getList(key).toArray();
        }
        return null;
    }

    @Override
    public boolean removeFromList(String key, int index) {
        try {
            client.getList(key).remove(index);
            return true;
        } catch (Exception ex) {
            log.error("", ex);
            return false;
        }
    }

    @Override
    public boolean removeList(String key) {
        return client.getList(key).delete();
    }

    @Override
    public int findObjectInList(String key, Object obj) {
        if (obj == null) {
            return -1;
        }
        Object[] objs = getArrayFromList(key);
        for (int i = 0; i < objs.length; i++) {
            Object tobj = objs[i];
            if (obj.equals(tobj)) {
                return i;
            }
        }
        return -1;
    }

    @Override
    public boolean compareAndSetObject(String key, Object expect, Object update) {
        return client.getBucket(key).compareAndSet(expect, update);
    }

    @Override
    public boolean putLong(String key, Long value, long cacheTime) {
        try {
            client.getAtomicLong(key).set(value);
            if (cacheTime > 0) {
                client.getAtomicLong(key).expire(cacheTime, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception ex) {
            log.error("", ex);
            return false;
        }
    }

    @Override
    public Long getLong(String key) {
        RAtomicLong atomicLong = client.getAtomicLong(key);
        if (atomicLong != null) {
            return atomicLong.get();
        }
        return null;
    }

    @Override
    public boolean removeLong(String key) {
        return client.getAtomicLong(key).delete();
    }

    @Override
    public Long addAndGetLong(String key, Long delta) {
        return client.getAtomicLong(key).addAndGet(delta);
    }

    @Override
    public Long getAndAddLong(String key, Long delta) {
        return client.getAtomicLong(key).getAndAdd(delta);
    }

    @Override
    public Long decrementAndGetLong(String key, Long delta) {
        return client.getAtomicLong(key).decrementAndGet();
    }

    @Override
    public Long getAndDecrementLong(String key, Long delta) {
        return client.getAtomicLong(key).getAndDecrement();
    }

    @Override
    public boolean setObjectToList(String key, int index, Object obj) {
        try {
            client.getList(key).set(index, obj);
            return true;
        } catch (Exception ex) {
            log.error("", ex);
            return false;
        }
    }

    @Override
    public boolean isExistList(String key) {
        return client.getList(key).isExists();
    }

    @Override
    public Collection<String> findKeyByPattern(String pattern) {
        Set<String> keys = new LinkedHashSet();
        Iterator<String> itor = client.getKeys().getKeysByPattern(pattern).iterator();
        while (itor.hasNext()) {
            keys.add(itor.next());
        }
        return keys;
    }

    @Override
    public boolean putObjectToMap(String name, String key, Object value, long cacheTime) {
        try {
            RMap<String, Object> rmap = client.getMap(name);
            rmap.put(key, value);
            if (cacheTime > 0) {
                client.getMap(name).expire(cacheTime, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception ex) {
            log.error("", ex);
            return false;
        }
    }

    @Override
    public Object getObjectFromMap(String name, String key) {
        RMap rmap = client.getMap(name);
        if (rmap != null) {
            return rmap.get(key);
        }
        return null;
    }

    @Override
    public Map<String, Object> getObjectsFromMap(String name, Set<String> keys) {
        RMap rmap = client.getMap(name);
        if (rmap != null) {
            return rmap.getAll(keys);
        }
        return null;
    }

    @Override
    public Set<String> getKeySetFromMap(String name) {
        RMap rmap = client.getMap(name);
        if (rmap != null) {
            return new LinkedHashSet<String>(rmap.keySet());
        }
        return null;
    }

    @Override
    public void removeKeysFromMap(String name, String[] keys) {
        RMap rmap = client.getMap(name);
        if (rmap != null) {
            rmap.fastRemove(keys);
        }

    }

    @Override
    public Object addAndGetToMap(String name, String key, Number delta) {
        RMap<String, Object> rmap = client.getMap(name);
        return rmap.addAndGet(key, delta);
    }

    @Override
    public boolean removeMap(String name) {
        RMap rmap = client.getMap(name);
        if (rmap != null) {
            return rmap.delete();
        }
        return true;
    }

    @Override
    public Set<Map.Entry<Object, Object>> getAllFromMap(String name) {
        RMap rmap = client.getMap(name);
        if (rmap != null) {
            return new LinkedHashSet<Map.Entry<Object, Object>>(rmap.entrySet());
        }
        return null;
    }

    @Override
    public Object getNativeCache() {
        return client;
    }

    @Override
    public long ttl(String key) {
        long ttl = client.getBucket(key).remainTimeToLive();
        return ttl;
    }
    public RedissonClient getRedisClient() {
        return client;
    }

}
